import axios from 'axios'
import { useUserStore } from '@/store/modules/user'
import { useRouter } from 'vue-router'
import { refreshToken, getConnToken } from '@/api/refreshToken'
import { SET_TOKEN, GET_TOKEN, REMOVE_TOKEN } from '@/utils/token'
import { ref } from 'vue'
import qs from 'qs'

const $router = useRouter()

// 是否正在刷新的标记
let isRefreshing = false
// 重试队列，每一项将是一个待执行的函数形式
let requests: any = []

let clientTokenSign: any = null
const loadingInstance: any = null

const requestConf = (config: any) => {
  // 1. 从pinia获取token数据
  const userStore = useUserStore()
  // 2. 按照后端的要求拼接token数据
  const token = userStore.token
  if (token) {
    // config.headers.Authorization = `Bearer ${token}`
    config.headers.token = token
    config.headers['xc_sso_sessionid'] = `${token}`
  }
  if (clientTokenSign) {
    config.headers['xc_client_sessionid'] = clientTokenSign
  }
  config.headers['transChannel'] = 'WEB'
  if (
    config.data &&
    config.headers['Content-Type'] ===
      'application/x-www-form-urlencoded;charset=UTF-8'
  )
    config.data = qs.stringify(config.data)
  return config
}

/**
 * 刷新刷新令牌
 * @param config 过期请求配置
 * @returns {any} 返回结果
 */
const tryRefreshToken = async (config: any) => {
  const userStore = useUserStore()
  if (!isRefreshing) {
    isRefreshing = true
    try {
      const {
        data: { token },
      } = await refreshToken()
      if (token) {
        // 替换token
        userStore.setToken(token)
        // 已经刷新了token，将所有队列中的请求进行重试
        requests.forEach((cb: any) => cb(token))
        // 重新请求完清空
        requests = []
        return service(requestConf(config))
      }
    } catch (error) {
      $router.push('/login')
    }
  } else {
    return new Promise((resolve) => {
      // 将resolve放进队列，用一个函数形式来保存，等token刷新后直接执行
      requests.push(() => {
        resolve(service(requestConf(config)))
      })
    })
  }
}

const refreshClientToken = async (config: any) => {
  if (!isRefreshing) {
    isRefreshing = true
    try {
      const res: any = await getConnToken({})
      const { clientToken } = res.result
      if (clientToken) {
        clientTokenSign = clientToken
        return service(requestConf(config))
      }
    } catch (error) {
      $router.push('/login')
    } finally {
      isRefreshing = false
    }
  } else {
    return new Promise((resolve) => {
      // 将resolve放进队列，用一个函数形式来保存，等token刷新后直接执行
      requests.push(() => {
        resolve(service(requestConf(config)))
      })
    })
  }
}

// 创建 axios 实例
const service = axios.create({
  baseURL: import.meta.env.VITE_APP_BASE_API,
  timeout: 60000,
  headers: {
    'Content-Type': 'application/json;charset=utf-8',
  },
})

// 请求拦截器
service.interceptors.request.use(requestConf, (error) => {
  return Promise.reject(error)
})

// 响应拦截器
service.interceptors.response.use(
  async (response) => {
    console.log(response)
    // 1. 从pinia获取token数据
    const userStore = useUserStore()
    const { config, data, status, statusText } = response
    // 接下来会在这里进行token过期的逻辑处理
    // 若data.code存在，覆盖默认code
    const code = data && data.code ? data.code : status
    if (loadingInstance) loadingInstance.close()
    switch (code) {
      case 200:
        return data
      case 401:
        // 清除仓库信息
        userStore.resetInfo()
        // 清除本地token
        REMOVE_TOKEN()
        // 跳转到登录页
        $router.push('/login')
        break
      case 402:
        return await tryRefreshToken(config)
      case 99994000:
        //无效链接，重新获取链接
        return await refreshClientToken(config)
      case 80000002:
        // 清除仓库信息
        userStore.resetInfo()
        // 清除本地token
        REMOVE_TOKEN()
        $router.push('/login')
        return
      case 403:
        $router.push('/403')
        break
    }
    return response.data
  },
  (error) => {
    console.log(error)
    return Promise.reject(error)
  },
)

// 导出 axios 实例
export default service
